import pandas as pd
from datetime import datetime, timedelta, time, date
import pytz
from typing import Dict, List, Tuple
from utils.multiplier import get_multiplier
import json
import os
from decimal import Decimal
from core.models import Order, Trade, Position
from adapters.platform_interface import PlatformAdapter
from storage.storage_interface import StorageInterface
import numpy as np

class TradeProcessor:
    """交易处理器"""
    
    def __init__(self, platform_adapter: PlatformAdapter, storage: StorageInterface):
        self.platform_adapter = platform_adapter
        self.storage = storage
        self.cur_positions: Dict[str, Position] = {}
        # 定义时区
        self.beijing_tz = pytz.timezone('Asia/Shanghai')
        self.chicago_tz = pytz.timezone('America/Chicago')

    @staticmethod
    def _get_nyse_trading_day(dt: datetime) -> date:
        """根据纽约时间判断纽约证券交易所的交易日（9:30 AM为分界点）"""
        if dt.time() >= time(9, 30):
            return dt.date()
        else:
            return (dt - timedelta(days=1)).date()
    
    def _get_existing_trades_count_for_day(self, ny_trading_day: date, before_datetime: datetime) -> int:
        """获取数据库中指定纽约交易日在指定时间之前的交易数量"""
        try:
            # 获取数据库中所有交易
            existing_trades = self.storage.get_trades()
            
            count = 0
            for trade in existing_trades:
                # 转换交易的开仓时间为纽约时间
                if hasattr(trade, 'open_datetime'):
                    open_dt = trade.open_datetime
                    if isinstance(open_dt, str):
                        open_dt = datetime.fromisoformat(open_dt.replace('Z', '+00:00'))
                    
                    # 假设数据库中的时间是北京时间
                    if open_dt.tzinfo is None:
                        open_dt_beijing = self.beijing_tz.localize(open_dt)
                    else:
                        open_dt_beijing = open_dt.astimezone(self.beijing_tz)
                    
                    # 转换为纽约时间
                    open_dt_ny = open_dt_beijing.astimezone(pytz.timezone('America/New_York'))
                    
                    # 计算纽约交易日
                    trade_ny_trading_day = self._get_nyse_trading_day(open_dt_ny)
                    
                    # 如果是同一交易日且时间在指定时间之前，计数+1
                    if trade_ny_trading_day == ny_trading_day and open_dt < before_datetime:
                        count += 1
            
            return count
        except Exception as e:
            print(f"查询已有交易数量时出错: {e}")
            return 0

    def _get_symbol_multiplier(self, symbol: str) -> float:
        """获取品种的乘数"""
        # 从完整symbol中提取基础品种（例如从MESM25中提取MES）
        base_symbol = symbol[:-3] if len(symbol) > 3 else symbol
        print(f"base_symbol: {base_symbol}")
        return get_multiplier(base_symbol)
        
    def _convert_time(self, time_val):
        """转换时间字符串为datetime对象，支持多种格式"""
        if isinstance(time_val, pd.Timestamp):
            if time_val.tzinfo is None:
                return time_val.tz_localize(self.beijing_tz)
            return time_val
        if isinstance(time_val, datetime):
            if time_val.tzinfo is None:
                return self.beijing_tz.localize(time_val)
            return time_val
        # 尝试不同的日期格式
        formats = [
            '%Y/%m/%d %H:%M',
            '%Y-%m-%d %H:%M:%S',
            '%Y/%m/%d %H:%M:%S',
            '%Y-%m-%d %H:%M'
        ]
        for fmt in formats:
            try:
                dt = datetime.strptime(time_val, fmt)
                dt = self.beijing_tz.localize(dt)
                return dt
            except Exception:
                continue
        raise ValueError(f"无法解析时间格式: {time_val}")

    def _get_session(self, dt: datetime) -> str:
        """根据时间判断交易时段"""
        # 转换为芝加哥时间
        chicago_time = dt.astimezone(self.chicago_tz)
        hour = chicago_time.hour
        
        if 8 <= hour < 15:  # 芝加哥时间8:00-15:00
            return 'RTH'
        else:
            return 'ETH'

    def _format_money(self, amount: float) -> str:
        """格式化金额，添加$符号"""
        return f"${amount:,.2f}"

    def _calculate_rrr(self, trade: Trade) -> None:
        """计算OpenRRR、CloseRRR、FWR、Actual Risk和PRR
        
        OpenRRR (OR) = 止盈距离/止损距离
        CloseRRR (CR) = 实际盈亏点数/止损距离 (保持正负号)
        FWR = 最大浮盈点/止损点位
        Actual Risk = 最大浮亏点/止损点位
        PRR = 后续最大盈利/止损点位
        
        注意：数据库中的take_profit_price和stop_loss_price存储的是相对距离，不是绝对价格
        """
        try:
            # 计算OpenRRR: 止盈距离/止损距离
            if (trade.take_profit_price is not None and 
                trade.stop_loss_price is not None and 
                trade.stop_loss_price > 0):  # 避免除零
                
                # 直接使用相对距离进行计算
                take_profit_distance = abs(trade.take_profit_price)
                stop_loss_distance = abs(trade.stop_loss_price)
                
                if stop_loss_distance > 0:
                    trade.open_rrr = round(take_profit_distance / stop_loss_distance, 2)
                else:
                    trade.open_rrr = None
            else:
                trade.open_rrr = None
            
            # 计算CloseRRR: 实际盈亏点数/止损距离 (保持正负号)
            if (trade.point_profit_per_lot is not None and 
                trade.stop_loss_price is not None and 
                trade.stop_loss_price > 0):
                
                # 使用实际盈亏点数（保持正负号）与止损距离的比值
                actual_points = trade.point_profit_per_lot  # 保持原始正负号
                stop_loss_distance = abs(trade.stop_loss_price)
                
                if stop_loss_distance > 0:
                    trade.close_rrr = round(actual_points / stop_loss_distance, 2)
                else:
                    trade.close_rrr = None
            else:
                trade.close_rrr = None
            
            # 计算FWR: 最大浮盈点/止损点位
            if (trade.max_floating_profit_points is not None and 
                trade.stop_loss_price is not None and 
                trade.stop_loss_price > 0):
                
                max_profit_points = trade.max_floating_profit_points
                stop_loss_distance = abs(trade.stop_loss_price)
                
                if stop_loss_distance > 0:
                    trade.fwr = round(max_profit_points / stop_loss_distance, 2)
                else:
                    trade.fwr = None
            else:
                trade.fwr = None
            
            # 计算Actual Risk: 最大浮亏点/止损点位
            if (trade.max_floating_loss_points is not None and 
                trade.stop_loss_price is not None and 
                trade.stop_loss_price > 0):
                
                max_loss_points = abs(trade.max_floating_loss_points)  # 取绝对值
                stop_loss_distance = abs(trade.stop_loss_price)
                
                if stop_loss_distance > 0:
                    trade.actual_risk = round(max_loss_points / stop_loss_distance, 2)
                else:
                    trade.actual_risk = None
            else:
                trade.actual_risk = None
            
            # 计算PRR: 后续最大盈利/止损点位
            if (trade.extend is not None and 
                trade.stop_loss_price is not None and 
                trade.stop_loss_price > 0):
                
                extend_points = trade.extend
                stop_loss_distance = abs(trade.stop_loss_price)
                
                if stop_loss_distance > 0:
                    trade.prr = round(extend_points / stop_loss_distance, 2)
                else:
                    trade.prr = None
            else:
                trade.prr = None
        
        except Exception as e:
            print(f"计算RRR、FWR、Actual Risk和PRR时出错: {e}")
            trade.open_rrr = None
            trade.close_rrr = None
            trade.fwr = None
            trade.actual_risk = None
            trade.prr = None

    def _create_trade(self, open_order: Order, close_order: Order, qty: int,
                     point_diff: float, multiplier: float) -> Trade:
        """创建交易记录"""
        direction = "Long" if open_order.side.lower() == "buy" else "Short"
        session = self.platform_adapter.get_session(open_order.open_time)
        
        # Helper to convert Decimal to float for SQLAlchemy Float columns
        def to_float_or_none(val):
            if isinstance(val, Decimal):
                return float(val)
            # If it's already a float, int, or None, just return it
            return val

        trade = Trade()
        trade.trade_id = str(open_order.order_id)+str(close_order.order_id)
        trade.symbol = open_order.symbol
        trade.open_datetime = open_order.close_time
        trade.open_price = to_float_or_none(open_order.avg_fill_price)
        trade.open_qty = to_float_or_none(qty)
        trade.close_datetime = close_order.close_time
        trade.close_price = to_float_or_none(close_order.avg_fill_price)
        trade.close_qty = to_float_or_none(qty)
        trade.direction = direction
        trade.open_order_type = open_order.order_type
        trade.close_order_type = close_order.order_type  # 记录平仓订单类型
        trade.trade_type = ""
        trade.side = None  # 默认为None，用户后续可以编辑
        trade.point_profit_per_lot = to_float_or_none(Decimal(str(point_diff)))
        trade.total_points = to_float_or_none(Decimal(str(point_diff * qty)))
        trade.gross_profit = to_float_or_none(Decimal(str(point_diff * qty * multiplier)))
        trade.net_profit = to_float_or_none(Decimal(str(point_diff * qty * multiplier - float(open_order.commission) - float(close_order.commission))))
        trade.commission = to_float_or_none(Decimal(str(float(open_order.commission) + float(close_order.commission))))
        trade.holding_time = str(close_order.close_time - open_order.close_time)
        trade.nth_trade = 0  # 默认为0，后续会计算
        trade.session = session
        trade.max_floating_profit_points = None
        trade.max_floating_profit_dollars = None
        trade.max_floating_loss_points = None
        trade.max_floating_loss_dollars = None
        trade.entry_reason = None
        trade.exit_reason = None
        trade.stop_loss_price = None
        trade.stop_loss_reason = None
        trade.take_profit_price = None
        trade.take_profit_reason = None
        trade.actual_risk = None
        trade.extend = None
        trade.prr = None
        
        # 自动填充最大浮盈点和最大浮亏点（基于离场理由）
        if trade.exit_reason == "达到目标位" and trade.point_profit_per_lot is not None:
            trade.max_floating_profit_points = abs(trade.point_profit_per_lot)
            # 重新计算最大浮盈金额
            if trade.max_floating_profit_points is not None and trade.open_qty is not None:
                trade.max_floating_profit_dollars = trade.max_floating_profit_points * trade.open_qty * multiplier
        
        if trade.exit_reason == "达到止损位" and trade.point_profit_per_lot is not None:
            trade.max_floating_loss_points = abs(trade.point_profit_per_lot)
            # 重新计算最大浮亏金额
            if trade.max_floating_loss_points is not None and trade.open_qty is not None:
                trade.max_floating_loss_dollars = trade.max_floating_loss_points * trade.open_qty * multiplier
        
        # 计算RRR、FWR、Actual Risk和PRR
        self._calculate_rrr(trade)
        
        return trade

    def _print_order_details(self, order: pd.Series):
        """打印订单详细信息"""
        print("\n订单详细信息:")
        print(f"  Order ID: {order['Order ID']}")
        print(f"  Symbol: {order['Symbol']}")
        print(f"  Side: {order['Side']}")
        print(f"  Type: {order['Type']}")
        print(f"  Quantity: {order['Quantity']}")
        print(f"  Filled: {order['Filled']}")
        print(f"  Quantity Left: {order['Quantity Left']}")
        print(f"  Limit: {order['Limit']}")
        print(f"  Stop: {order['Stop']}")
        print(f"  Avg Fill Price: {order['Avg Fill Price']}")
        print(f"  Status: {order['Status']}")
        print(f"  Open Time: {order['Open Time']}")
        print(f"  Close Time: {order['Close Time']}")
        print(f"  Duration: {order['Duration']}")
        print(f"  Commission: {order['Commission']}")
        print(f"  Expiration: {order['Expiration']}")
        print(f"  Multiplier: {order['Multiplier']}")

    def _print_trade_details(self, trade: pd.Series):
        """打印交易详细信息"""
        print("\n交易详细信息:")
        print(f"  Symbol: {trade['symbol']}")
        print(f"  Trade ID: {trade['id']}")
        print(f"  Open DateTime: {trade['open_datetime']}")
        print(f"  Open Price: {trade['open_price']}")
        print(f"  Open Quantity: {trade['open_qty']}")
        print(f"  Close DateTime: {trade['close_datetime']}")
        print(f"  Close Price: {trade['close_price']}")
        print(f"  Close Quantity: {trade['close_qty']}")
        print(f"  Direction: {trade['direction']}")
        print(f"  Open Order Type: {trade['open_order_type']}")
        print(f"  Trade Type: {trade['trade_type']}")
        print(f"  Point Profit Per Lot: {trade['point_profit_per_lot']}")
        print(f"  Total Points: {trade['total_points']}")
        print(f"  Gross Profit: {trade['gross_profit']}")
        print(f"  Net Profit: {trade['net_profit']}")
        print(f"  Commission: {trade['commission']}")
        print(f"  Holding Time: {trade['holding_time']}")
        print(f"  Nth Trade: {trade['nth_trade']}")
        print(f"  Session: {trade['session']}")
        print(f"  Max Floating Profit Points: {trade['max_floating_profit_points']}")
        print(f"  Max Floating Profit Dollars: {trade['max_floating_profit_dollars']}")
        print(f"  Max Floating Loss Points: {trade['max_floating_loss_points']}")
        print(f"  Max Floating Loss Dollars: {trade['max_floating_loss_dollars']}")
        print(f"  Entry Reason: {trade['entry_reason']}")
        print(f"  Exit Reason: {trade['exit_reason']}")
        print(f"  Stop Loss Price: {trade['stop_loss_price']}")
        print(f"  Stop Loss Reason: {trade['stop_loss_reason']}")
        print(f"  Take Profit Price: {trade['take_profit_price']}")
        print(f"  Take Profit Reason: {trade['take_profit_reason']}")

    def _handle_new_position(self, symbol: str, order: Order, qty: int):
        """处理新开仓"""
        print("当前无持仓，新订单为开仓")
        self.cur_positions[symbol] = Position(
            symbol=symbol,
            position=qty,
            trades=[{
                'order': order,
                'remaining_qty': abs(qty)
            }]
        )
        print(f"更新后持仓: {self.cur_positions[symbol].position}")

    def _handle_add_position(self, symbol: str, order: Order, qty: int):
        """处理加仓"""
        print("加仓操作")
        self.cur_positions[symbol].trades.append({
            'order': order,
            'remaining_qty': abs(qty)
        })
        self.cur_positions[symbol].position += qty
        print(f"更新后持仓: {self.cur_positions[symbol].position}")

    def _handle_reduce_position(self, symbol: str, order: Order, qty: int, 
                              pending_trades: List[Trade], new_trades: List[Trade]) -> int:
        """处理减仓或反手"""
        print("减仓或反手操作")
        remaining_qty = abs(qty)
        while remaining_qty > 0:
            if self.cur_positions[symbol].trades:
                open_trade = self.cur_positions[symbol].trades[-1]
                open_order = open_trade['order']
                match_qty = min(remaining_qty, open_trade['remaining_qty'])
                print(f"匹配数量: {match_qty}")
                
                point_diff = float(order.avg_fill_price) - float(open_order.avg_fill_price)
                if self.cur_positions[symbol].position < 0:
                    point_diff = -point_diff
                print(f"点差: {point_diff}")
                
                trade = self._create_trade(
                    open_order, order, match_qty,
                    point_diff, float(order.multiplier)
                )
                print(f"创建交易记录: 开仓价={trade.open_price}, 平仓价={trade.close_price}, 数量={trade.open_qty}")
                
                if not self.storage.is_trade_duplicate(trade):
                    print("新交易记录")
                    pending_trades.append(trade)
                else:
                    print("重复交易记录")
                
                open_trade['remaining_qty'] -= match_qty
                remaining_qty -= match_qty
                print(f"剩余数量: {remaining_qty}")
                
                if open_trade['remaining_qty'] <= 0:
                    print("移除已完全匹配的开仓订单")
                    self.cur_positions[symbol].trades.pop()
            else:
                print(f"反手操作，剩余数量: {remaining_qty}")
                self.cur_positions[symbol].trades.append({
                    'order': order,
                    'remaining_qty': remaining_qty
                })
                break
        
        self.cur_positions[symbol].position += qty
        print(f"更新后持仓: {self.cur_positions[symbol].position}")
        
        return remaining_qty

    def process_new_orders(self, raw_orders_df: pd.DataFrame) -> Dict:
        """处理新的订单数据"""
        print("\n=== 开始处理新订单 ===")
        print(f"输入订单数量: {len(raw_orders_df)}")
        
        # 转换为标准订单格式
        orders = self.platform_adapter.convert_to_orders(raw_orders_df)
        orders = [order for order in orders if order.status.lower() == 'filled']
        print(f"已完成的订单数量: {len(orders)}")
        
        # 按时间排序
        orders.sort(key=lambda x: (x.close_time, x.open_time))
        if orders:
            print("\n订单时间范围:")
            print(f"最早订单时间: {orders[0].close_time}")
            print(f"最晚订单时间: {orders[-1].close_time}")
        
        new_trades = []
        new_orders = []
        pending_trades = []
        pending_orders = []
        duplicate_orders = []
        duplicate_trades = []
        
        for i, order in enumerate(orders, 1):
            print(f"\n--- 处理第 {i} 个订单 ---")
            print(f"订单信息: Symbol={order.symbol}, Side={order.side}, Filled={order.filled}, Price={order.avg_fill_price}")
            print(f"开仓时间: {order.open_time}, 平仓时间: {order.close_time}")
            
            if not self.storage.is_order_duplicate(order):
                print("新订单，继续处理")
                pending_orders.append(order)
                
                symbol = order.symbol
                print(f"symbol: {symbol}")
                qty = int(float(order.filled))
                if str(order.side).lower() == 'sell':
                    qty = -qty
                print(f"处理数量: {qty}")
                
                if symbol not in self.cur_positions:
                    print(f"初始化 {symbol} 的持仓信息")
                    self.cur_positions[symbol] = Position(
                        symbol=symbol,
                        position=0,
                        trades=[]
                    )
                
                cur_pos = self.cur_positions[symbol].position
                print(f"当前持仓: {cur_pos}")
                
                remaining_qty = abs(qty)
                
                print(f"获取 {symbol} 的乘数")
                multiplier = self.platform_adapter.get_symbol_multiplier(symbol)
                print(f"乘数为: {multiplier}")
                
                if cur_pos == 0:
                    self._handle_new_position(symbol, order, qty)
                else:
                    if (qty > 0 and cur_pos > 0) or (qty < 0 and cur_pos < 0):
                        self._handle_add_position(symbol, order, qty)
                    else:
                        remaining_qty = self._handle_reduce_position(symbol, order, qty, pending_trades, new_trades)
                
                if remaining_qty == 0 and self.cur_positions[symbol].position == 0:
                    new_orders.extend(pending_orders)
                    new_trades.extend(pending_trades)
                    
                    print("new_orders: ", new_orders)
                    print("new_trades: ", new_trades)
                    
                    pending_trades = []
                    pending_orders = []
            else:
                print("重复订单，跳过处理")
                duplicate_orders.append(order)
        
        # 保存新交易和订单（重要：先保存trade，再保存order）
        save_orders_result = None
        save_trades_success = False
        
        if new_trades:
            print("\n=== 保存新交易 ===")
            print(f"新交易数量: {len(new_trades)}")
            
            # 首先根据开仓时间对new_trades进行升序排列
            print("📅 按开仓时间升序排列新交易...")
            new_trades.sort(key=lambda trade: trade.open_datetime)
            print(f"✅ 交易排列完成，时间范围: {new_trades[0].open_datetime} ~ {new_trades[-1].open_datetime}")

            # 计算nth_trade - 需要考虑数据库中已有的交易
            trades_df_for_nth = pd.DataFrame([t.__dict__ for t in new_trades])
            if 'open_datetime' in trades_df_for_nth.columns:
                trades_df_for_nth['open_datetime'] = pd.to_datetime(trades_df_for_nth['open_datetime'])
                # 确保 open_datetime 是时区感知的，然后转换为纽约时区
                if trades_df_for_nth['open_datetime'].dt.tz is None:
                    trades_df_for_nth['open_datetime_ny'] = trades_df_for_nth['open_datetime'].dt.tz_localize(self.beijing_tz).dt.tz_convert(pytz.timezone('America/New_York'))
                else:
                    trades_df_for_nth['open_datetime_ny'] = trades_df_for_nth['open_datetime'].dt.tz_convert(pytz.timezone('America/New_York'))

                # 计算纽约交易日
                trades_df_for_nth['ny_trading_day'] = trades_df_for_nth['open_datetime_ny'].apply(self._get_nyse_trading_day)
                
                # 按交易日和开仓时间排序（DataFrame用于nth_trade计算）
                trades_df_for_nth = trades_df_for_nth.sort_values(by=['ny_trading_day', 'open_datetime'])
                
                # 为每个新交易计算nth_trade，需要考虑数据库中已有的交易
                for i, trade in enumerate(new_trades):
                    ny_trading_day = trades_df_for_nth.loc[i, 'ny_trading_day']
                    open_datetime = trades_df_for_nth.loc[i, 'open_datetime']
                    
                    # 查询数据库中同一纽约交易日的已有交易数量
                    existing_trades_count = self._get_existing_trades_count_for_day(ny_trading_day, open_datetime)
                    
                    # 计算当前交易在同一交易日中的序号
                    same_day_new_trades = trades_df_for_nth[
                        (trades_df_for_nth['ny_trading_day'] == ny_trading_day) & 
                        (trades_df_for_nth['open_datetime'] <= open_datetime)
                    ]
                    current_day_sequence = len(same_day_new_trades)
                    
                    # nth_trade = 已有交易数量 + 当前交易在新交易中的序号
                    trade.nth_trade = existing_trades_count + current_day_sequence

            try:
                self.storage.save_trades(new_trades)
                save_trades_success = True
                print("新交易已保存")
            except Exception as e:
                error_msg = f"保存交易失败: {e}"
                print(error_msg)
                save_trades_success = False
                # 检查是否是重复trade_id错误
                if "UNIQUE constraint failed" in str(e) or "duplicate key" in str(e).lower():
                    # 抛出更具体的异常，让GUI能够捕获并显示
                    raise ValueError(f"检测到重复的交易ID，无法保存交易。请检查数据是否已经导入过。\n详细错误: {e}")
                else:
                    # 其他类型的错误也抛出
                    raise e
        else:
            save_trades_success = True  # 没有交易需要保存，视为成功
        
        # 只有在交易保存成功后，才保存订单
        if save_trades_success and new_orders:
            print("\n=== 保存新订单 ===")
            print(f"新订单数量: {len(new_orders)}")
            save_orders_result = self.storage.save_orders(new_orders)
            print("新订单保存完成")
        elif not save_trades_success and new_orders:
            print("\n=== 跳过保存订单 ===")
            print("由于交易保存失败，跳过订单保存以避免数据不一致")
            # 创建一个表示失败的结果
            save_orders_result = {
                'success': False,
                'saved_count': 0,
                'duplicate_count': 0,
                'duplicate_orders': [],
                'error': '由于交易保存失败，跳过订单保存以避免数据不一致'
            }
        
        # 重置所有持仓信息
        for symbol in self.cur_positions:
            self.cur_positions[symbol] = Position(
                symbol=symbol,
                position=0,
                trades=[]
            )
        print("\n=== 处理完成 ===")
        
        # 返回详细结果
        result = {
            'new_trades': new_trades,
            'duplicate_orders': duplicate_orders,
            'duplicate_trades': duplicate_trades,
            'save_orders_result': save_orders_result,
            'save_trades_success': save_trades_success
        }
        
        return result

    def calculate_statistics(self, trades_df: pd.DataFrame, max_n: int = 5) -> Dict:
        """计算多维度交易统计信息，支持最大N笔盈亏统计（全部按美东交易日分组）"""
        if trades_df.empty:
            return {}

        # 统一净利润为数值
        trades_df['net_profit_value'] = trades_df['net_profit']
        
        # 确保 'net_profit_value' 是数值，强制转换错误为NaN
        trades_df['net_profit_value'] = pd.to_numeric(trades_df['net_profit_value'], errors='coerce')
        trades_df = trades_df.dropna(subset=['net_profit_value']) # 删除无法转换为数值的行

        if trades_df.empty: # 检查删除NaN后DataFrame是否为空
            return {}

        # 资金曲线
        trades_df = trades_df.sort_values('open_datetime')
        trades_df['equity_curve'] = trades_df['net_profit_value'].cumsum()
        equity_curve_labels = trades_df['open_datetime'].astype(str).tolist()

        # === 美东交易日分组 ===
        tz_ny = pytz.timezone('America/New_York')
        
        # FIX: 添加 errors='coerce' 处理无法解析的日期时间字符串
        trades_df['open_datetime'] = pd.to_datetime(trades_df['open_datetime'], errors='coerce')
        
        # 删除 open_datetime 无法解析为 NaT 的行
        trades_df = trades_df.dropna(subset=['open_datetime'])
        
        if trades_df.empty: # 检查删除NaT后DataFrame是否为空
            return {}

        # 确保 datetime 对象具有时区信息。
        # 如果 open_datetime 是时区不敏感的（naive），先将其本地化（例如，到UTC）。
        # ORM datetime 对象默认可能是 naive。
        if trades_df['open_datetime'].dt.tz is None:
            print("open_datetime is naive --")
            print("Original datetime:", trades_df['open_datetime'].iloc[0])
            print("After SH localization:", trades_df['open_datetime'].dt.tz_localize('Asia/Shanghai').iloc[0])
            print("After NY conversion:", trades_df['open_datetime'].dt.tz_localize('Asia/Shanghai').dt.tz_convert(tz_ny).iloc[0])
            trades_df['open_datetime_ny'] = trades_df['open_datetime'].dt.tz_localize('Asia/Shanghai').dt.tz_convert(tz_ny)
        else:
            print("open_datetime is not naive")
            trades_df['open_datetime_ny'] = trades_df['open_datetime'].dt.tz_convert(tz_ny)

        trades_df['ny_trading_day'] = trades_df['open_datetime_ny'].apply(self._get_nyse_trading_day).astype(str)
        trades_df['ny_week'] = trades_df['open_datetime_ny'].dt.strftime('%Y-%U')
        trades_df['ny_month'] = trades_df['open_datetime_ny'].dt.strftime('%Y-%m')
        trades_df['ny_year'] = trades_df['open_datetime_ny'].dt.year

        def basic_stats(df):
            total = len(df)
            win = (df['net_profit_value'] > 0).sum()
            loss = (df['net_profit_value'] < 0).sum()
            win_rate = win / total * 100 if total else 0
            avg_win = df[df['net_profit_value'] > 0]['net_profit_value'].mean() if win else 0
            avg_loss = df[df['net_profit_value'] < 0]['net_profit_value'].mean() if loss else 0
            profit_factor = abs(avg_win / avg_loss) if avg_loss != 0 else None
            return {
                'total_trades': total,
                'winning_trades': win,
                'losing_trades': loss,
                'win_rate': win_rate,
                'avg_win': avg_win,
                'avg_loss': avg_loss,
                'profit_factor': profit_factor,
                'total_profit': df['net_profit_value'].sum(),
                'equity_curve': df['equity_curve'].tolist(),
                'equity_curve_labels': df['open_datetime'].astype(str).tolist(),
                'max_n_loss': df.nsmallest(max_n, 'net_profit_value').to_dict('records'),
                'max_n_win': df.nlargest(max_n, 'net_profit_value').to_dict('records')
            }

        # Session统计
        session_stats = {}
        for session in ['RTH', 'ETH']:
            session_stats[session] = basic_stats(trades_df[trades_df['session'] == session])

        # Direction统计（做多/做空）
        direction_stats = {}
        for direction in ['Long', 'Short']:
            direction_stats[direction] = basic_stats(trades_df[trades_df['direction'] == direction])

        # Side统计（开仓侧）
        side_stats = {}
        for side in ['Left', 'Right', 'Mid']:
            side_stats[side] = basic_stats(trades_df[trades_df['side'] == side])

        # 按美东交易日/周/月/年分组
        daily_stats = {str(date): basic_stats(group) for date, group in trades_df.groupby('ny_trading_day')}
        weekly_stats = {str(week): basic_stats(group) for week, group in trades_df.groupby('ny_week')}
        monthly_stats = {str(month): basic_stats(group) for month, group in trades_df.groupby('ny_month')}
        yearly_stats = {str(year): basic_stats(group) for year, group in trades_df.groupby('ny_year')}

        # 总体统计
        overall = basic_stats(trades_df)

        # 符号统计
        symbols_stats = {}
        for symbol in trades_df['symbol'].unique():
            symbol_trades = trades_df[trades_df['symbol'] == symbol]
            symbols_stats[symbol] = basic_stats(symbol_trades)

        def to_py(obj):
            if isinstance(obj, dict):
                return {k: to_py(v) for k, v in obj.items()}
            elif isinstance(obj, list):
                return [to_py(v) for v in obj]
            elif isinstance(obj, (np.integer, )):
                return int(obj)
            elif isinstance(obj, (np.floating, )):
                return float(obj)
            elif isinstance(obj, (np.ndarray, )):
                return obj.tolist()
            else:
                return obj

        result = {
            'overall': overall,
            'session': session_stats,
            'direction': direction_stats,
            'side': side_stats,
            'daily': daily_stats,
            'weekly': weekly_stats,
            'monthly': monthly_stats,
            'yearly': yearly_stats,
            'symbols': symbols_stats
        }
        return to_py(result) 